<!DOCTYPE html>
<html>
    <head>
        <title>Waiting for a key.</title>
        <script src="encrypted-media-utils.js"></script>
        <script src="../../resources/testharness.js"></script>
        <script src="../../resources/testharnessreport.js"></script>
    </head>
    <body>
        <video></video>
        <script>
            // For debugging timeouts, keep track of the number of the
            // various events received.
            var debugEncryptedEventCount = 0;
            var debugWaitingForKeyEventCount = 0;
            var debugTimeUpdateEventCount = 0;
            var debugMessage = '';

            promise_test(function(test)
            {
                var video = document.querySelector('video');
                var content = '../content/test-encrypted.webm';
                var initData;
                var initDataType;
                var mediaKeySession;

                test.timeout = function()
                {
                    var message = 'timeout. message = ' + debugMessage
                                   + ', encrypted: ' + debugEncryptedEventCount
                                   + ', waitingforkey: ' + debugWaitingForKeyEventCount
                                   + ', timeupdate: ' + debugTimeUpdateEventCount;
                    test.force_timeout();
                    test.timeout_id = null;
                    test.set_status(2, message);
                    test.done();
                };

                // As this code doesn't wait for the 'message' event to avoid
                // race conditions with 'waitingforkey', specify the key ID and
                // key used by the encrypted content.
                var keyId = stringToUint8Array('0123456789012345');
                var rawKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
                                             0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);

                return navigator.requestMediaKeySystemAccess('org.w3.clearkey', getConfigurationForFile(content)).then(function(access) {
                    debugMessage = 'createMediaKeys()';
                    return access.createMediaKeys();
                }).then(function(mediaKeys) {
                    debugMessage = 'setMediaKeys()';
                    return video.setMediaKeys(mediaKeys);
                }).then(function() {
                    video.src = content;
                    video.play();
                    debugMessage = 'wait_for_encrypted_event()';
                    return wait_for_encrypted_event(video);
                }).then(function(e) {
                    // Received the 'encrypted' event(s), so keep a copy of
                    // the initdata for use when creating the session later.
                    initData = e.initData;
                    initDataType = e.initDataType;

                    // Wait until the video indicates that it needs a key to
                    // continue.
                    debugMessage = 'wait_for_waitingforkey_event()';
                    return wait_for_waitingforkey_event(video);
                }).then(function() {
                    // Make sure the video is NOT paused and not progressing
                    // before a key is provided. This requires the video
                    // to NOT have a clear lead.
                    assert_false(video.paused);
                    assert_equals(video.currentTime, 0);

                    // Create a session.
                    mediaKeySession = video.mediaKeys.createSession();
                    debugMessage = 'generateRequest()';
                    return mediaKeySession.generateRequest(initDataType, initData);
                }).then(function() {
                    // generateRequest() will cause a 'message' event to
                    // occur specifying the keyId that is needed, but we
                    // ignore it since we already know what keyId is needed.
                    // Add the key needed to decrypt.
                    var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, rawKey)));
                    debugMessage = 'update()';
                    return mediaKeySession.update(jwkSet);
                }).then(function() {
                    // Video should start playing now that it can decrypt the
                    // streams, so wait until a little bit of the video has
                    // played.
                    debugMessage = 'wait_for_timeupdate_event()';
                    return wait_for_timeupdate_event(video);
                });

                // Typical test duration is 6 seconds on release builds
                // (12 seconds on debug). Since the test is timing out anyway,
                // make the duration 5 seconds so that the timeout function
                // is actually called (instead of simply aborting the test).
            }, 'Waiting for a key.', { timeout: 5000 });

            // Wait for a pair of 'encrypted' events. Promise resolved on
            // second event.
            function wait_for_encrypted_event(video)
            {
                var encryptedEventCount = 0;
                return new Promise(function(resolve) {
                    video.addEventListener('encrypted', function listener(e) {
                        assert_equals(e.target, video);
                        assert_true(e instanceof window.MediaEncryptedEvent);
                        assert_equals(e.type, 'encrypted');

                        // The same decryption key is used by both the audio
                        // and the video streams so wait for the second event
                        // to ensure we see both events.
                        ++debugEncryptedEventCount;
                        if (++encryptedEventCount != 2)
                            return;

                        video.removeEventListener('encrypted', listener);
                        resolve(e);
                    });
                });
            };

            // Wait for a 'waitingforkey' event. Promise resolved when the
            // event is received.
            function wait_for_waitingforkey_event(video)
            {
                var waitingForKeyEventCount = 0;
                return new Promise(function(resolve) {
                    video.addEventListener('waitingforkey', function listener(e) {
                        assert_equals(e.target, video);
                        assert_equals(e.type, 'waitingforkey');

                        ++debugWaitingForKeyEventCount;
                        ++waitingForKeyEventCount;
                        // TODO(jrummell): waitingforkey event should only
                        // occur once. http://crbug.com/461903
//                      assert_equals(waitingForKeyEventCount, 1, 'Multiple waitingforkey events');

                        video.removeEventListener('waitingforkey', listener);
                        resolve(e);
                    });
                });
            };

            // Wait for a 'timeupdate' event. Promise resolved if |video| has
            // played for more than 0.2 seconds.
            function wait_for_timeupdate_event(video)
            {
                return new Promise(function(resolve) {
                    video.addEventListener('timeupdate', function listener(e) {
                        assert_equals(e.target, video);
                        ++debugTimeUpdateEventCount;
                        if (video.currentTime < 0.2)
                            return;
                        video.removeEventListener('timeupdate', listener);
                        resolve(e);
                    });
                });
            };
        </script>
    </body>
</html>
